package com.xflib.framework.util;

import java.io.File;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 动态 java.lib.path 扩展管理工具
 * Usage:
 *   DynamicJavaLibraryPathUtil.create()
 *                 .extend("/home/user/lib")
 *                 .extend("/tmp/lib"))
 *                 .build();
 */
public class DynamicJavaLibraryPathUtil {

    private static Field field;
    private static Set<String> path = new HashSet<>();
    private boolean isModified=false;

    private DynamicJavaLibraryPathUtil(){}

    /**
     * 获取 实例
     * @return
     */
    public static DynamicJavaLibraryPathUtil create(){
        return new DynamicJavaLibraryPathUtil();
    }

    /**
     * 扩展路径(添加到缓存)
     * @param ePath
     * @return
     */
    public DynamicJavaLibraryPathUtil extend(String ePath){
        File file =new File(ePath);
        if(file.exists()) {
            if (file.isDirectory()) {
                _add(file.getAbsolutePath());
            } else if (file.isFile()) {
                File file1=new File(file.getParent());
                _add(file1.getAbsolutePath());
            }
        }
        return this;
    }

    /**
     * 使扩展生效
     */
    public void build(){
        if(isModified) {
            String[] tmp = path.toArray(new String[0]);
            try {
                /*
                 重新加载系统属性，使之生效。原理是 ClassLoader 的一下2个私有属性仅仅在初始化时设置，需要重置，否则不生效
                 usr_paths = initializePath("java.library.path");
                 sys_paths = initializePath("sun.boot.library.path"); 即java.exe的存储路径
                 这种方法同样适用于.dll或.so的动态加载路径设置
                */
                field.set(null, tmp);
                System.setProperty("java.library.path", String.join(File.pathSeparator,path));
                this.isModified=false;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    private void _add(String ePath){
        boolean _isModified=path.add(ePath);
        if(_isModified) {
            this.isModified = _isModified;
        }

    }

    public static String getUserPath() {
        String[] paths = new String[0];
        try {
            paths = (String[]) field.get(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return String.join(";",paths);
    }
    public static String getJavaLibraryPath() {
        return System.getProperty("java.library.path");
    }


    static {
        try {
            // 缓存 usr_paths
            field = ClassLoader.class.getDeclaredField("usr_paths");
            field.setAccessible(true);
            String[] paths = (String[]) field.get(null);
            path.addAll(Arrays.asList(paths));

            // 缓存 java.library.path
            String newLibPath=System.getProperty("java.library.path");
            path.addAll(Arrays.asList(newLibPath.split(File.pathSeparator)));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }
}
